package kgame5.enginex {
import kgame5.enginex.event.SendCommandEvent;
import kgame5.kutil.FPSMonitor;
import kgame5.kutil.KKey;
import kgame5.kutil.T;

import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.utils.Dictionary;

/**
 * @author kk
 * 保持gameWorld:Proxy
 * 保持GameCommand:Command
 * 保持视图:View?
 * 提供稳定帧频
 * 
 * --
 * 缺陷是，摄像机还没有作为一个GameUnit加入到体系中。它算是一个GameActor,有自己的FSM
 * 
 * demo
 * starup()
 * regsterCommand()
 * 调用command添加各个实体
 * 
 * --
 * EventDispatcher是为了GamePlay能向外部发送事件。比如提示“一大批敌人接近”.或者通知LevelManger说有坦克被销毁
 */
public class GamePlayX extends EventDispatcher{
	
	private var mc:Sprite;//只是用来装载efh用的,装载3d视图的
	
	private var gameWorld:GameWorldX;//逻辑游戏世界，持有各个GameUnit,并执行更新
	
	//一个保证逻辑帧频，保证不会因为低帧频而丢掉逻辑update()
	private var loop:GameLoopX;
	
	//命令
	private var dict_commands:Dictionary;//dict[commandName]=GameCommand
	
	//mc_c是最外层容器,放在构造函数里是比getDO()要好，防止遗失
	public function GamePlayX(viewportWidth:int,viewportHeight:int,frameRate:int=20,bDebug:Boolean=true){
		
		mc=new Sprite();
		
		
		gameWorld=new GameWorldX(mc,viewportWidth,viewportHeight,bDebug);
		
		//
		loop=new GameLoopX(frameRate);
		
		//注册命令 
		dict_commands=new Dictionary();	
		
		//调试,显示帧频
		if(bDebug){
			mc.addChild(new FPSMonitor(frameRate,frameRate*0.7));
		}
		
		//捕获按键
		if(mc.stage!=null){
			ats(null);
		}else{
			mc.addEventListener(Event.ADDED_TO_STAGE, ats);
		}
	}
	public function getDO():DisplayObject{
		return mc;
	}
	
	private function ats(e:Event):void{
		T.p(this,"被添加到舞台");
		KKey.Init(mc.stage);
	}
	
//	//被command直接添加粒子用
//	public function getView():GameView{
//		return viewComp;
//	}
	
	//添加粒子之类的用
	public function getWorld():GameWorldX{
		return gameWorld;
	}
	
	//注册各个commands,被外部用
	public function registerCommand(commandName:String,cmd:GameCommand):void{
		dict_commands[commandName]=cmd;
		cmd.setGamePlay(this);
		cmd.addEventListener(SendCommandEvent.TYPE, onSendCommandEvent);
	}
	
	//这个被其他调用,注意需要被子类继承
	public function startup(CC:int,RC:int,CellSize:int):void{
		
		gameWorld.init(CC,RC,CellSize);
		
		loop.start();
		mc.addEventListener(Event.ENTER_FRAME, efh);//efh
		
		KKey.Clear();//清空一下输入
	}
	
	//使用完了则销毁
	public function dispose():void{
		
		gameWorld.clear();
		
		//efh停止
		mc.removeEventListener(Event.ENTER_FRAME, efh);
	}
	
	//主要是会被command调用
	public function addEntity(ent:Entity):void{
		gameWorld.addEntity(ent);
		ent.addEventListener(SendCommandEvent.TYPE, onSendCommandEvent);
	}
	
	public function removeEntity(entID:int):void{
		gameWorld.removeEntity(entID);
		var ent:Entity=gameWorld.findEntity(entID);
		if(ent!=null){
			ent.removeEventListener(SendCommandEvent.TYPE, onSendCommandEvent);
		}
	}
	
	private function onSendCommandEvent(e:SendCommandEvent):void{
		executeCommand(e.commandName, e.data);
	}
	
	//被外部执行某个Command,比如被网络调用，或者是被其他Mediator通知。
	//注意，这个是作为Mediator里的一个comp集成到pureMVC中的
	public function executeCommand(commandName:String,data:Object):void{
		var gc:GameCommand=dict_commands[commandName] as GameCommand;
		if(gc!=null){
			gc.execute(data);
		}
	}
	
	private function efh(e:Event):void {
		//1,计算丢失的帧
		var lostCount:int=loop.lostFrameCount();
		//2,补上丢失的帧
		for(var i:int=0;i<lostCount;i++){
			gameWorld.onTick();
		}
		
		//3，渲染，注意这个是3d引擎计算，不需要补上丢失的帧
		gameWorld.onFrame();
	}
	
}//end of class
}
